#!/bin/sh
JAVA_OPTS=""
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote"
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.port=9999"
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.ssl=false"
exec java $JAVA_OPTS -jar jajmx.jar -nocompdaemon -usejavacp -savecompiled "$0" "$@"
!#
import jajmx._
import javax.management.openmbean.CompositeData

val host = if (args.size>=1) args(0) else "localhost" 
val port = if (args.size>=2) args(1).toInt else 9999

case class ThreadLock(name:String, ownerId:Option[Long], ownerName:Option[String])

case class ThreadInfo(name:String, id:Long, state:String,lock:Option[ThreadLock],
                      blockedCount:Long, waitedCount:Long)

object ThreadInfo {
  def apply(ti:CompositeData) :ThreadInfo = {
	  val id           = ti.get("threadId").toString.toLong
	  val name         = ti.get("threadName").toString
	  val state        = ti.get("threadState").toString
	  val blockedCount = ti.get("blockedCount").toString.toLong
	  val waitedCount  = ti.get("waitedCount").toString.toLong
	  val lock = Option(ti.get("lockName")) map {_.toString} filter {_.size>0} collect {
	               case lockName =>
	                   val lockOwnerId = Option(ti.get("lockOwnerId")) map {_.asInstanceOf[Long]} filterNot {_ == -1}
	                   val lockOwnerName = Option(ti.get("lockOwnerName")) map {_.toString.trim}
	                   ThreadLock(lockName, lockOwnerId, lockOwnerName)
	             }
	  ThreadInfo(name, id, state, lock, blockedCount, waitedCount)
  }
}

JMX.once(host,port) { jmx =>
  for (threading <- jmx.threading ;
       ids <- threading.get[Array[Long]]("AllThreadIds") ;
       rawThreadsInfos <- threading.call[Array[CompositeData]]("getThreadInfo", ids)) {
    val threadsInfos = rawThreadsInfos.toList filterNot {_ == null} filter {_.get("threadId")!=null} map {ThreadInfo(_)}
    val countByState = threadsInfos groupBy {_.state} map { case (s,l) => s -> l.size}
    val countByStateStr = countByState map {case (s,l) => s+":"+l} mkString " "
    println("Total %d  %s".format(threadsInfos.size, countByStateStr))
    for ( ti <- threadsInfos sortBy {_.id } ) {
      println("%d - %s - %s".format(ti.id, ti.state, ti.name) )
    }
  }
}

